Skip to content

docs(adr): seed manifest as durable per-root state#546

Merged
PolyphonyRequiem merged 3 commits into
mainfrom
adr/seed-manifest-as-durable-state
May 29, 2026
Merged

docs(adr): seed manifest as durable per-root state#546
PolyphonyRequiem merged 3 commits into
mainfrom
adr/seed-manifest-as-durable-state

Conversation

@PolyphonyRequiem

Copy link
Copy Markdown
Owner

Summary

Captures the design for the seed manifest — durable per-root JSON state
that makes polyphony seeding restart-friendly without trusting corrupt
state.

Greenlit by Daniel on 2026-05-29 after a four-lens team debate
(architecture / engine / verb-error / platform).

What's in the ADR

  • Concept and lifecycle of the seed manifest
  • JSON schema with field-by-field definitions
  • Reconciliation algorithm (marker-based, using existing polyphony:plan-child-id)
  • Rich plan_generation linkage for renegotiation orphan detection
  • Script-internal retry circuit (3 attempts on infra failures)
  • New seeding_blocked terminal vs. workflow_abandoned
  • Explicit non-goals (no GitHub, no platform abstraction, no engine changes)
  • 5 open follow-up questions

Related

Status

Accepted. Implementation work tracked separately — this PR is the ADR only.

Daniel Green and others added 3 commits May 24, 2026 23:16
The watermark tag formatter PolyphonyTags.RunStartedAt(DateTimeOffset) was
called only in tests; production never wrote the tag. Per
docs/decisions/run-reset.md the watermark is supposed to be stamped by
reset (originally polyphony reset state, collapsed into
polyphony reset root by AB#3308). The pattern->projection rewrite
preserved the delete half of the state phase
(ProjectionResetCatalog.cs:24, AdoWorkItemTagDeleter.cs:74-77) but
dropped the stamp half. As a result, every detect-state /
state next-ready call saw runStartedAt=null, the
`mergedAt <= watermark` filter never fired, and any root with a prior
merged plan PR was stuck in merged_unseeded forever.

Introduces IRunWatermarkStamper / RunWatermarkStamper(ITwigClient) and
wires it into ProjectionResetExecutor as the action of the state
phase: when Execute && !SkipState, after the per-resource delete loop
body, stamp a fresh polyphony:run-started-at=<UtcNow> tag (mirroring
AdoWorkItemTagDeleter's sync-show-patch-sync pattern, defensively
stripping any pre-existing watermark tags first).

Fail-loud posture: twig exceptions propagate to the executor's outer
catch, which records `state` in stepsFailed. Symmetric to
PlanObserver.ReadRunStartedAtAsync's fail-closed read posture.

Tests (9 added):
- RunWatermarkStamperTests: no-prior, replaces, dedups duplicates,
  enforces sync-show-patch-sync order, throws when twig.show returns null.
- ProjectionResetExecutorTests: Execute mode stamps once; dry-run
  doesn't stamp; SkipState doesn't stamp; stamper throw marks state
  phase failed.

Dogfood verification: cloudvault root 62365430, reset --execute
--allow-unjournaled stamps polyphony:run-started-at=2026-05-25T... and
plan detect-state flips from merged_unseeded to not_started.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Polyphony PRs are agent-authored under the operator's PAT, so the PR's
author_identity is the human operator. The prior rule 'comment author ==
PR author identity -> exclude' silently dropped the operator's own review
threads -- exactly the human-in-the-loop intervention the loop must
respect. Marker presence (PrCommentMarker) is the deterministic signal
for bot-vs-human under a shared identity; identity-equality is not.

Removes the identity-exclusion rule from the analyzer prompt in all three
workflows (plan-level, github-pr, ado-pr) and from their load-bearing
header comments. Vote rules no longer use the 'non-author reviewer'
qualifier -- self-approval / self-changes-requested is a platform
branch-protection concern, not the analyzer's.

ADR: docs/decisions/pr-feedback-identity-classification.md

Validation: all four lints (sentiment-loop-consistency, github-pr,
ado-pr, plan-level) and all 76 Pester tests across their .Tests.ps1
files pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds ADR `seed-manifest-as-durable-state.md` capturing the design synthesized
from the four-lens debate (Bach/Mahler/Mozart/Sibelius/Beethoven) and
greenlit by Daniel on 2026-05-29.

Key decisions encoded:
- Seed manifest at `.polyphony/state/{rootId}/seed-manifest.json`
  with atomic writes (`.tmp` + rename).
- `polyphony:plan-child-id` marker as the canonical reconciliation
  primitive (no title hashing).
- Rich `plan_generation` linkage `{id, parent, cause, created_at}`
  with manifest items carrying `introduced_in` for orphan detection
  across renegotiation.
- Script-internal retry (3 attempts on exit codes 3 and 5; code 1
  permanent) — `max_attempts` is not available on `type: script`
  conductor nodes.
- New `seeding_blocked` terminal, distinct from `workflow_abandoned`
  (which is reserved for operator-volitional abandonment).
- GitHub explicitly out of scope; ADO-only execution.
- Verb evolution on `plan write-plan` and `plan seed-children` — no
  new verb names.

Open follow-up questions documented in §11 of the ADR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PolyphonyRequiem PolyphonyRequiem merged commit 619ce7c into main May 29, 2026
1 check passed
@PolyphonyRequiem PolyphonyRequiem deleted the adr/seed-manifest-as-durable-state branch May 29, 2026 20:43
PolyphonyRequiem pushed a commit that referenced this pull request May 31, 2026
- Merged PR #546 (seed-manifest ADR) at 619ce7c
- Merged PR #547 (PR-gate compression + Liszt bug fixes) at eab39cb
- Inbox decision entry merged into decisions.md
- Cross-agent history notes appended to Bach, Wagner, Liszt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant